package rtsp;

import entity.rtsp.RTSPRequestEntity;
import entity.rtsp.RTSPResponseEntity;
import org.apache.commons.lang3.StringUtils;
import sun.java2d.pipe.OutlineTextRenderer;
import utils.Consts;
import utils.RTPPortManager;
import utils.RTSPPacketParser;
import utils.RTSPUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Set;

public class RTSPMainThread implements Runnable {
    private Socket sourceRTSPConnection;
    private Socket targetRTSPConnection;
    private Set<UDPRetransmitter> retransmitters;

    public RTSPMainThread(Socket socket){
        this.sourceRTSPConnection = socket;
        retransmitters = new HashSet<>(4);
    }

    @Override
    public void run() {
        boolean isTeardown = false;
        try {
            targetRTSPConnection = new Socket(InetAddress.getByName(Consts.getProp("rtsp.destIp")), Integer.parseInt(Consts.getProp("rtsp.destPort")));
            InputStream sourceInput = sourceRTSPConnection.getInputStream();
            OutputStream sourceOutput = sourceRTSPConnection.getOutputStream();
            InputStream targetInput = targetRTSPConnection.getInputStream();
            OutputStream targetOutput = targetRTSPConnection.getOutputStream();

            while(!isTeardown){
                RTSPRequestEntity rtspRequestEntity = RTSPPacketParser.getInstance().requestEntityParser(sourceInput);
                if(rtspRequestEntity == null){
                    break;
                }
                System.out.println("Receive RTSP Request:\r\n" + rtspRequestEntity.toString());
                RTSPUtils.requestDecorator(rtspRequestEntity);


                if("SETUP".equals(rtspRequestEntity.getMethod()) && StringUtils.isNotEmpty(rtspRequestEntity.getHeaders().get("Transport"))){
                    String clientPort = RTPPortManager.getClientPort();
                    String serverPort = RTPPortManager.getServerPort();
                    String sourceClientPort = RTSPUtils.getClientPort(rtspRequestEntity.getHeaders().get("Transport"));

                    rtspRequestEntity.getHeaders().put("Transport",
                            rtspRequestEntity.getHeaders().get("Transport").replace("client_port=" + sourceClientPort, "client_port=" + clientPort));

                    RTSPUtils.requestPacketSend(rtspRequestEntity, targetOutput);
                    RTSPResponseEntity rtspResponseEntity = RTSPPacketParser.getInstance().responseEntityParser(targetInput);
                    System.out.println("Receive RTSP Response:\r\n" + rtspResponseEntity);
                    String targetServerPort = RTSPUtils.getServerPort(rtspResponseEntity.getHeaders().get("Transport"));

                    rtspResponseEntity.getHeaders().put("Transport",
                            rtspResponseEntity.getHeaders().get("Transport").replace("client_port=" + clientPort, "client_port=" + sourceClientPort)
                                .replace("server_port=" + targetServerPort, "server_port=" + serverPort));

                    UDPRetransmitter.udpRetransmitterCreator(
                            clientPort,
                            serverPort,
                            targetServerPort,
                            sourceClientPort,
                            Consts.getProp("rtsp.destIp"),
                            "127.0.0.1",
                            retransmitters);
                    RTSPUtils.responsePacketSend(rtspResponseEntity, sourceOutput);

                }else{
                    RTSPUtils.requestPacketSend(rtspRequestEntity, targetOutput);
                    RTSPResponseEntity rtspResponseEntity = RTSPPacketParser.getInstance().responseEntityParser(targetInput);
                    System.out.println("Receive RTSP Response:\r\n" + rtspResponseEntity);

                    //由于DESCRIBE方法的响应报文的body里会附带数据流的地址，所以要替换成本地地址
                    if ("DESCRIBE".equals(rtspRequestEntity.getMethod())){
                        rtspResponseEntity.setBody(
                                rtspResponseEntity.getBody().replace(
                                        "rtsp://" + Consts.getProp("rtsp.destIp") + ":" + Consts.getProp("rtsp.destPort")
                                        , "rtsp://127.0.0.1:" + Consts.getProp("rtsp.listen") ));
                    }

                    RTSPUtils.responsePacketSend(rtspResponseEntity, sourceOutput);
                    if ("TEARDOWN".equals(rtspRequestEntity.getMethod())){
                        isTeardown = true;
                        retransmitters.stream().forEach(x -> x.endRetransmit());
                    }
                }

            }


            sourceInput.close();
            sourceOutput.close();
            targetInput.close();
            targetOutput.close();

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            try {
                sourceRTSPConnection.close();
                targetRTSPConnection.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }


}
